GCC -g 原因
gcc test.cpp -o test -g
调试选项,因此在一般需要进行程序调试的场景下,我们都会加上该选项,并且根据调试工具的不同,还能直接选择更有针对性的说明。
加上-g选项以后,gcc在编译是会做以下额外的操作:
-
创建符号表,符号表包含了程序中使用的变量名称的列表。
-
关闭所有的优化机制,以便程序执行过程中严格按照原来的C代码进行。
如果编译时,没有加-g,用gdb调试结果:
如果编译时,加了-g选项,则会保留相关调试信息:
objdump -h xxx
返回xxx程序各程序段地址
调试流程
- gdb -q xxx
- disassemble main : 查看main函数的汇编代码
- b *main+21 : 在离main 21的位置下断点
寄存器
gdb中,命令: info registers
堆栈指针r13(SP):每一种异常模式都有其自己独立的r13,它通常指向异常模式所专用的堆栈,也就是说五种异常模式、非异常模式(用户模式和系统模式),都有各自独立的堆栈,用不同的堆栈指针来索引。这样当ARM进入异常模式的时候,程序就可以把一般通用寄存器压入堆栈,返回时再出栈,保证了各种模式下程序的状态的完整性。
SP, the Stack Pointer
Register R13 is used as a pointer to the active stack.
sp就是栈顶指针。 x $sp 可以查看指针内容: 0x7efff684
LR :是用于保存函数调用的返回地址的link register。
LR, the Link Register
Register R14 is used to store the return address from a subroutine. At other times, LR can be used for other purposes.
PC(它显示下一个指令的地址)
当执行一个调用,称为分支链接指令bl时,返回地址放在r14(链接寄存器)中。程序计数器pc更改为您要分支的地址。
我当前断的地址就是在 main+32
ASLR地址
/proc/sys/kernel/randomize_va_space
关闭ASLR:
sudo echo 0 > /proc/sys/kernel/randomize_va_space
gef自带数据生成器
用nano打开原文件,如下:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, char **argv)
{
char buffer[64];
printf("input: \n");
gets(buffer);
}
利用pattern create 100 生成100个字符,可以看到PC值为“raaa”,通过pattern search 找到溢出点,确定溢出点为68:
详见动图
ROP
git clone --recursive https://github.com/JonathanSalwan/ROPgadget.git
ROPgadget来从代码中提取gadget,接下来工具会对所有提取出来的gadget进行分析,并计算语义,然后将分析结果存储在一个gadget数据库中。
是一种新型的基于代码复用技术的攻击,攻击者从已有的库或可执行文件中提取指令片段,构建恶意代码。
ROP的核心思想:攻击者扫描已有的动态链接库和可执行文件,提取出可以利用的指令片段(gadget),这些指令片段均以ret指令结尾,即用ret指令实现指令片段执行流的衔接。
ROPgadget --binary libc-2.13.so --only “pop” | grep r0
而ROP攻击则是利用以ret结尾的程序片段 ,操作这些栈相关寄存器,控制程序的流程,执行相应的gadget,实施攻击者预设目标 。ROP不同于retum-to-libc攻击之处在于**,ROP攻击以ret指令结尾的函数代码片段 ,而不是整个函数本身去完成预定的操作。**从广义角度讲 ,return-to-libc攻击是ROP攻的特例。最初ROP攻击实现在x86体系结构下,随后扩展到各种体系结构.。与以往攻击技术不同的是,ROP恶意代码不包含任何指令,将自己的恶意代码隐藏在正常代码中。
ARM中函数参数是优先通过寄存器传递,如果寄存器不够了,再用栈。
Intel寄存器:%esp和 %ebp寄存器维护栈顶指针和栈帧的起始地址 ,%eip是程序计数器寄存器
程序调用系统库查询
在断点后,使用r运行后,运行vmmap可以查看当前程序的系统调用库,如红线就是libc的基地址。
要想知道/bin/sh的在内存的地址: 0x7efff8c5
system函数地址:
详见链接:
https://www.freebuf.com/articles/terminal/107276.html
查看系统libc版本
执行命令: sudo find / -name “libc.so.6” 找到 libc.so.6
pi路径是:/lib/arm-linux-gnueabihf/
可以看到libc是2.28版本,然后在该目录就能找到该libc。
必须切到该目录下,针对libc,执行下面命令:
ROPgadget --binary libc-2.28.so
如果不加限制范围的话,那么会搜索整个库里的gadget,这大概有28551个,肯定不是想要的。
所以,缩小范围,只找到r0寄存器上有关关键key: ‘pop’相关的gadget。
ROPgadget --binary libc-2.28.so --only 'pop' | grep r0
这样就只有两个:
这个gadget还是满足需求的: 能控制r0及pc。
然后在gef调试程序中,用vmmap,找到libc的基地址。
libc在内存的基地址是:0x76e54000
而我们在libc找到的需要的gadget偏移地址(offset address)是:
0x000da9e4 : pop {r0, r1, r2, r3, fp, pc}
0x000da9e4
那我们要的gadget在内存中的真正地址 = 基地址 + 偏移地址,即:
0x76e54000 + 0x000da9e4 = 0x76F2E9E4
socat
socat [options] <address> <address>
options可以查看help。
address有一下几种形式:
- STDIN STDOUT :表示标准输入输出,可以就用一个横杠代替
/var/log/syslog : 也可以是任意路径,如果是相对路径要使用./,打开一个文件作为数据流。 - TCP:127.0.0.1:1080 : 建立一个TCP连接作为数据流,TCP也可以替换为UDP
- TCP-LISTEN:12345 : 建立TCP监听端口,TCP也可以替换为UDP
- EXEC:/bin/bash : 执行一个程序作为数据流。
场景1:
socat tcp-listen:6666,fork exec:./exploit &
tcp-listen:xxxx 表示监听本地某个端口
fork exec: 表示fork一个程序的进程
‘&’ 表示程序在后台运行
场景2:
我想在目标机(服务器端)上弄一个shell代理,在服务器端输入一下命令(大小写都行):
服务器端:
sudo socat tcp-listen:6666 exec:/bin/bash
服务器端结果:结尾没有加&的话,就是显示在运行中
客户端输入命令:
socat - tcp:192.168.2.101:6666
客户端结果,直接连接后,就可以在反弹shell里输入命令了,查看服务器中文件目录内容了
查看系统多少位
getconf LONG_BIT
然后回车,就会返回系统的位数。
查看系统当前已安装软件
查看系统中安装的所有软件,可以通过:
dpkg -l
查看某个软件是否安装,可以通过grep来进行提取。
dpkg -l | grep vim
要查看已安装软件的安装位置,可以使用dpkg命令的大写的-L参数。
dpkg -L vim
另外,安装的软件都是可执行程序,可以通过which命令来查看,如果已经安装会提示程序安装的位置。
which vim